#pragma once

#include "../Console/ConsoleWindow.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	DynamicArray  </Summary>
/// 
/// <purpose>	Contiguous memory container	</purpose>
////////////////////////////////////////////////////////////////////////////////////////////////////

template <typename T>
class DynamicArray
{
	unsigned int	size;
	unsigned int	capacity;
	T*				items;

public:

	DynamicArray();

	DynamicArray( unsigned int reserve );

	~DynamicArray();

	DynamicArray( const DynamicArray& ref ); 

	DynamicArray& operator=( const DynamicArray& ref );

public:

	T& operator[]( unsigned int index );

	void Clear();

	void Push_Back( T item );

	T& Pop_Back();

	void Insert( T item, unsigned int index );

	void Erase( unsigned int index );

	void MemCopy( T* items, unsigned int size );

	void Reserve( unsigned int amount = 0 );

public:

	unsigned int GetSize() const { return size; }

	unsigned int GetCapacity() const { return capacity; }

public:

	friend ConsoleWindow& operator<<(ConsoleWindow& out, const DynamicArray& arr)
	{
		for(unsigned i = 0; i < arr.size; ++i)
		{
			out << "INDEX: " << i << " - ITEM: " << arr.items[i] << "\n";
		}

		return out;
	}
};








template<typename T>
DynamicArray<T>::DynamicArray( ) : size(0), capacity(0), items(NULL)
{
}

template<typename T>
DynamicArray<T>::~DynamicArray( )
{
	delete[] items;
}

template<typename T>
DynamicArray<T>::DynamicArray( unsigned int reserve ) : size(0), capacity(0), items(NULL)
{
	Reserve(reserve);
}

template<typename T>
DynamicArray<T>::DynamicArray( const DynamicArray<T>& ref )
{
	size = ref.size;
	capacity = ref.capacity;

	items = new T[capacity];

	for(unsigned i = 0; i < size; ++i)
		items[i] = ref.items[i];
}

template<typename T>
DynamicArray<T>& DynamicArray<T>::operator=( const DynamicArray<T>& ref )
{
	if(this != &ref)
	{
		Clear();
		size = ref.size;
		capacity = ref.capacity;

		items = new T[capacity];

		for(unsigned i = 0; i < size; ++i)
			items[i] = ref.items[i];
	}
	return *this;
}

template<typename T>
T& DynamicArray<T>::operator[]( unsigned int index )
{
	return items[index];
}

template<typename T>
void DynamicArray<T>::Clear( )
{
	size = 0;
	capacity = 0;
	delete[] items;
	items = 0;
}

template<typename T>
void DynamicArray<T>::Push_Back( T item )
{
	if(size == capacity)
		Reserve();

	items[size] = item;
	size++;
}

template<typename T>
T& DynamicArray<T>::Pop_Back()
{
	size--;
	return items[size];
}

template<typename T>
void DynamicArray<T>::Insert( T item, unsigned int index )
{
	if(size == capacity)
		Reserve();

	size++;

	for(unsigned i = size; i > index; --i)
	{
		items[i] = items[i - 1];
	}

	items[index] = item;
}

template<typename T>
void DynamicArray<T>::Erase( unsigned int index )
{
	size--;

	for(unsigned i = index; i < size; ++i)
	{
		items[i] = items[i + 1];
	}
}

template<typename T>
void DynamicArray<T>::MemCopy( T* items, unsigned int size )
{
	Clear();

	Reserve(size);

	this->size = size;
	this->items = new T[size];

	memcpy(this->items, items, size); 
}

template<typename T>
void DynamicArray<T>::Reserve( unsigned int amount = 0 )
{
	if (amount == 0 && capacity > 0)
		amount = capacity * 2;
	else if (amount == 0 && capacity == 0)
		amount = 1;
	else if(amount < capacity)
		return;

	capacity = amount;

	T* tempItems = new T[capacity];

	for(unsigned i = 0; i < size; ++i)
		tempItems[i] = items[i];

	delete[] items;
	items = tempItems;
}

